/**
 * Created by pefish on 2017/6/17.
 */

import mysql from 'mysql'
import DataProvider from './DataProvider'
import moment from 'moment'
import log4js from 'log4js'
import Person from './Person'

const logger = log4js.getLogger();
const api_key = '***'
const secret_key = '****'
const depthNumForSum = 6
const anaDepthNum = 10
const anaIntervalPerDepthSum = 6  // 几个小决策分析大决策一次
const limitPercent = 90  // 判断涨跌的临界百分比
const percentSpan = 40 // 定义涨幅是否大的标准
const freezeTime = 60 * 1000

class DataCollector {
  constructor (conn) {
    this._symbol = 'ltc_cny' // btc_cny: 比特币 ltc_cny: 莱特币 eth_cny :以太坊
    this.conn = conn
    this._dataProvider = new DataProvider(api_key, secret_key)
    this._person = null
  }

  async _getAccountInfo () {
    const sql = `select * from account_info order by id desc limit 0, 1`
    const results = await this._query(sql)
    if (results && results.length > 0) {
      return results[0]
    } else {
      return null
    }
  }

  async start () {
    const accountInfo = await this._getAccountInfo()
    if (accountInfo) {
      this._person = new Person(accountInfo['cny'], accountInfo['ltc'], accountInfo['last_in_price'])
    } else {
      this._person = new Person(2000, 0, 0)
      this._saveAccountInfo()
    }
    // 开启循环保存数据
    this._saveDepthData()
    setInterval(this._saveDepthData.bind(this), 8000)

    // 开启循环分析数据并做出决策
    setInterval(this._anala.bind(this), 8000 * anaIntervalPerDepthSum)
  }

  async _anala () {
    const results = await this._getLastDepthRecord(anaDepthNum)
    const zhangResults = results.filter((result) => {
      return result['result'] === 1
    })

    const dieResults = results.filter((result) => {
      return result['result'] === -1
    })
    if (zhangResults.length < 2 && dieResults.length < 2) {
      logger.warn(`${zhangResults.length}:${dieResults.length} 变化不明显，不动`, this._person.toString())
      return
    }

    if (zhangResults.length - dieResults.length > 2) {
      // 决策 涨
      logger.warn(`${zhangResults.length}:${dieResults.length} 要涨了`, this._person.toString())
      this._afterAsc()
    } else if (dieResults.length - zhangResults.length > 2) {
      // 决策跌
      logger.warn(`${zhangResults.length}:${dieResults.length} 要跌了`, this._person.toString())
      this._afterDesc()
    } else {
      logger.warn(`${zhangResults.length}:${dieResults.length} 变化不明显，不动`, this._person.toString())
    }
  }

  async _afterDesc () {
    if (Date.now() - this._lastDecideTime < freezeTime && this._lastDecide === 1) {
      // 如果5分钟内这次决策与上次决策相反，则不算数
      logger.warn('5分钟内这次决策与上次决策相反，不算数')
      return
    }

    if (this._person.ltc > 1) {
      // 执有ltc
      // 可能亏也可能赚，存入数据库
      const last = await this._getLastPrice()
      const win = (last - this._person.lastInPrice) * this._person.ltc
      const fee = this._person.ltc * last * 2 /1000
      // 只有赚钱了才卖掉
      if (win > fee) {
        const sql = `insert into win (win, time, last_in_price, out_price, num, fee) values (${win}, '${moment(Date.now()).format('YYYY-MM-DD HH:mm:ss')}', ${this._person.lastInPrice}, ${last}, ${this._person.ltc}, ${fee})`
        await this._query(sql)
        this._person.cny = this._person.ltc * last - fee // 手续费
        this._person.ltc = 0
        this._saveAccountInfo()
        logger.warn('全部卖掉, ' + win.toString(), this._person.toString())
      } else {
        logger.warn('赚不到钱, 不卖 ' + win.toString(), this._person.toString())
      }
    } else {
      // 执有cny,不动
      logger.warn('执有cny,不动', this._person.toString())
    }
    this._lastDecide = -1 // 保存上次的最终决策
    this._lastDecideTime = Date.now() // 保存上次决策的时间
  }

  async _saveAccountInfo () {
    const sql = `insert into account_info (cny, ltc, last_in_price, time) values (${this._person.cny}, ${this._person.ltc}, ${this._person.lastInPrice}, '${moment(Date.now()).format('YYYY-MM-DD HH:mm:ss')}')`
    await this._query(sql)
  }

  async _afterAsc () {
    if (Date.now() - this._lastDecideTime < freezeTime && this._lastDecide === -1) {
      // 如果5分钟内这次决策与上次决策相反，则不算数
      logger.warn('5分钟内这次决策与上次决策相反，不算数')
      return
    }

    if (this._person.ltc > 1) {
      // 执有ltc
      logger.warn('执有ltc,不动', this._person.toString())
      // 不动
    } else {
      // 全部买入
      const last = await this._getLastPrice()
      this._person.ltc = this._person.cny / last - this._person.cny * 2 / 1000 / last // 手续费
      this._person.cny = 0
      this._person.lastInPrice = last // 记录此次买入价格
      this._saveAccountInfo()
      logger.warn('全部买入', this._person.toString())
    }
    this._lastDecide = 1 // 保存上次的最终决策
    this._lastDecideTime = Date.now() // 保存上次决策的时间
  }

  async _getLastPrice () {
    const ticker = await this._dataProvider.getTicker()
    return ticker['ticker']['last']
  }

  async _saveDepthData () {
    const data = await this._dataProvider.getDepth()
    // 卖单
    const asks = data['asks'].slice(data['asks'].length - depthNumForSum, data['asks'].length)
    // 买单
    const bids = data['bids'].slice(data['bids'].length - depthNumForSum, data['bids'].length)
    let askSum = asks.reduce((prev, cur, index, arr) => {
      return ['sum', prev[1] + cur[1]]
    })[1]
    askSum = Number.parseFloat(askSum.toFixed(3))
    let bidSum = bids.reduce((prev, cur, index, arr) => {
      return ['sum', prev[1] + cur[1]]
    })[1]
    bidSum = Number.parseFloat(bidSum.toFixed(3))

    let askPercent = ((askSum / (askSum + bidSum)) * 100)
    askPercent = Number.parseFloat(askPercent.toFixed(2))
    let bidPercent = ((bidSum / (askSum + bidSum)) * 100)
    bidPercent = Number.parseFloat(bidPercent.toFixed(2))
    // 考虑突然卖或买深度变化大的情况
    if (askPercent > limitPercent) {
      const lastSixRecords = await this._getLastDepthRecord(anaDepthNum)
      for (let record of lastSixRecords) {
        if (askPercent - record['ask_percent'] > percentSpan) {
          // 卖深度涨幅大于40,决策跌
          logger.warn('卖深度涨幅大,要跌了')
          this._afterDesc()
          break
        }
      }
    }
    if (bidPercent > limitPercent) {
      const lastSixRecords = await this._getLastDepthRecord(anaDepthNum)
      for (let record of lastSixRecords) {
        if (bidPercent - record['bid_percent'] > percentSpan) {
          // 买深度涨幅大于40,决策涨
          logger.warn('买深度涨幅大,要涨了')
          this._afterAsc()
          break
        }
      }
    }
    const result = askPercent > limitPercent ? -1 : (bidPercent > limitPercent ? 1 : 0)
    const mark = askPercent > limitPercent ? '跌' : (bidPercent > limitPercent ? '涨' : '平')

    const last = await this._getLastPrice()
    logger.info(`卖深度：${askSum},           买深度：${bidSum},           卖百分比：${askPercent},           买百分比：${bidPercent},           决策：${mark},           最新价：${last}`)
    const sql = `insert into depth_data (ask_sum, bid_sum, ask_percent, bid_percent, num, time, result, mark) values (${askSum}, ${bidSum}, ${askPercent}, ${bidPercent}, ${depthNumForSum}, '${moment(Date.now()).format('YYYY-MM-DD HH:mm:ss')}', ${result}, '${mark}')`
    await this._query(sql)
  }

  async _getLastDepthRecord (num) {
    const sql = `select * from depth_data order by id desc limit 0, ${num}`
    return await this._query(sql)
  }

  async _query (sql) {
    return new Promise((resolve, reject) => {
      this.conn.query(sql, (err, results, fields) => {
        // logger.info(sql)
        if (err) {
          logger.error('插入深度信息到数据库出错', err)
          reject()
        }
        resolve(results)
      })
    })
  }

}



const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '',
  database: 'auto_trade'
})

connection.connect((err) => {
  if (err) {
    logger.error('error connecting: ' + err.stack)
    process.exit(1)
  }
  logger.info('connected as id ' + connection.threadId)
  new DataCollector(connection).start()
})
